#import <Foundation/Foundation.h>
#import <deque>
#import <list>
#import <map>
#import "Common.h"

enum ImageCacheEntryStatus { JUST_CREATED, DOWNLOADING, FAILED_DOWNLOAD, LOADING, LOADED };

@class ImageCache;

@protocol ImageCacheDelegate

-(void)imageCache:(ImageCache *)cache image:(UIImage *)image statusChanged:(ImageCacheEntryStatus)status forUrl:(NSURL *)url;

@end

@interface UIImageViewCached : UIImageView<ImageCacheDelegate> {
    NSPtr<UIImage> empty_image;
    NSPtr<NSURL> url;
    NSPtr<NSURL> thumbnail_url;
    NSPtr<UIImage> url_image;
    NSPtr<UIImage> thumbnail_image;
}

-(void)cancelLoad;
-(void)setURL:(NSURL *)url;
-(void)setURL:(NSURL *)url thumbnailURL:(NSURL *)thumbnail_url;

@end


@protocol ImageCacheDelegate;

typedef std::list< id<ImageCacheDelegate> > ImageCacheDelegates;


struct ImageCacheEntry
{
	ImageCacheEntry()
    : status(JUST_CREATED)
	{}
	NSPtr<UIImage> image;
	ImageCacheEntryStatus status;
	ImageCacheDelegates delegates;
};

/*struct LoadOrSaveStruct
{
	NSPtr<NSString> url;
	NSPtr<NSData> data; // if this is not 0, first save data to file
};*/

struct NSPtrNSURLLess { // simple comparison function
	bool operator()(const NSPtr<NSURL> & a, const NSPtr<NSURL> & b)
	{
		return [[a.get() absoluteString] compare:[b.get() absoluteString]] < 0;
	}
};

typedef std::map< NSPtr<NSURL>, ImageCacheEntry, NSPtrNSURLLess > CacheType;


@interface ImageCache : NSObject {
	NSPtr<NSString> cache_path_current;
	NSPtr<NSString> cache_path_old;

    CacheType memory_cache;

	std::deque< NSPtr<NSURL> > waiting_download;
	std::deque< NSPtr<NSURL> > failed_download;

    NSPtr<NSOperationQueue> load_save_queue;
}

-(id)initWithClearInterval:(NSTimeInterval)clear_interval_seconds;

+(ImageCache *)instance;

-(UIImage *)startLoadingImageforUrl:(NSURL *)url withDelegate:(id<ImageCacheDelegate>)dg;
-(void)stopLoadingImageforUrl:(NSURL *)url withDelegate:(id<ImageCacheDelegate>)dg;

@end

/*#import "ImageCacheDownloader.h"

@protocol ImageCacheDelegate;

typedef std::list< id<ImageCacheDelegate> > ImageCacheDelegates;

enum ImageCacheEntryStatus { JUST_CREATED, DOWNLOADING, FAILED_DOWNLOAD, LOADING, LOADED };

struct ImageCacheEntry
{
	ImageCacheEntry():
		status(JUST_CREATED)
	{}
	NSPtr<UIImage> image;
	ImageCacheEntryStatus status;
	ImageCacheDelegates delegates;
};

struct LoadOrSaveStruct
{
	NSPtr<NSString> url;
	NSPtr<NSData> data; // if this is not 0, first save data to file
};

typedef std::map< NSPtr<NSString>, ImageCacheEntry, NSPtrNSStringLess > CacheType;

@interface ImageCache : NSObject {
	NSPtr<NSString> cache_path_current;
	NSPtr<NSString> cache_path_old;

	CacheType memory_cache;

	std::deque< NSPtr<ImageCacheDownloader> > active_downloaders;
	std::deque< NSPtr<ImageCacheDownloader> > passive_downloaders;

	NSPtr<NSConditionLock> queueLock;
	std::deque< LoadOrSaveStruct > waiting_load;

	NSPtr<NSThread> worker;

	id<ImageCacheDelegate> delegate;
}

@property (nonatomic, assign) id<ImageCacheDelegate> delegate;

-(NSString *)pathForUrl:(NSString *)url old:(NSString **)old_path;
-(NSString *)nameForUrl:(NSString *)url;
-(void)imageLoadedFromDisk:(NSArray *)arr;
-(void)downloadNext;
-(void)downloadComplete:(ImageCacheDownloader *)downloader url:(NSString *)url withData:(NSData *)data;
-(void)broadcastImageChanged:(ImageCacheEntry *)image forUrl:(NSString *)url;
-(void)didReceiveMemoryWarning;

-(id)initWithClearInterval:(NSTimeInterval)clear_interval_seconds;
-(void)wait_termination;
-(void)attempt_failed_downloads;

-(void)startDownloadingImageforUrl:(NSString *)url;
-(ImageCacheEntry *)startLoadingImageforUrl:(NSString *)url withDelegate:(id<ImageCacheDelegate>)dg;
-(void)stopLoadingImageforUrl:(NSString *)url withDelegate:(id<ImageCacheDelegate>)dg;

@end

@protocol ImageCacheDelegate

-(void)imageCache:(ImageCache *)cache imageChanged:(ImageCacheEntry *)entry forUrl:(NSString *)url;

@end
*/